
// Custom manifest removed the following assets:
// 1. res/raw-assets/2a/2a40e5e7-4c4a-4350-9e5d-76757755cdd2.png
// 2. res/raw-assets/2d/2d86a854-63c4-4b90-8b88-a4328b8526c2.png
// So when custom manifest used, you should be able to find them in downloaded remote assets
import LanguageMngTs from "../Managers/LanguageMngTs";

var customManifestStr = JSON.stringify({
    "packageUrl": "http://192.168.50.220:5555/tutorial-hot-update/remote-assets/",
    "remoteManifestUrl": "http://192.168.50.220:5555/tutorial-hot-update/remote-assets/project.manifest",
    "remoteVersionUrl": "http://192.168.50.220:5555/tutorial-hot-update/remote-assets/version.manifest",
    "version": "1.0.0",
    "assets": {},
    "searchPaths": []
});

cc.Class({
    extends: cc.Component,

    properties: {
        logLabel:cc.Label  ,
        manifestUrl: {
            type: cc.Asset,
            default: null
        },
        _updating: false,
        _canRetry: false,
        _storagePath: '',
        _indicateLabel:null,
    },

    setLog:function (string) {
        if(this.logLabel){
            this.logLabel.string += string
        }
    },

    initGateHotUpdate:function (gateMgr) {
        if(!gateMgr){
            cc.error("No gate mgr")
            return
        }
        this.gateMgr = gateMgr
    },

    changeIndicatorLabel:function (string) {
        cc.log("gate hot update:",string)
        this.gateMgr.changeIndicatorLabel(string)
    },

    showUpdateProgress:function () {
        this.gateMgr.showGateProgress(true)
    },

    changeUpdateProgress:function (percent) {
        this.gateMgr.changeGateUpdateProgress(percent)
    },

    checkCb: function (event) {
        cc.log('Code: ' + event.getEventCode());
        let isNewest = false
        let needHotUpdate = false
        let cannotUpdate = false
        switch (event.getEventCode())
        {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                // this.logLabel.string += "No local manifest file found, hot update skipped.\n";
                this.changeIndicatorLabel(LanguageMngTs.getSentence(375))   //
                cannotUpdate = true
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
                this.changeIndicatorLabel(LanguageMngTs.getSentence(376))    //Downing manifest error.
                cannotUpdate = true
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                // this.logLabel.string += "Fail to download manifest file, hot update skipped.\n";
                this.changeIndicatorLabel(LanguageMngTs.getSentence(377))    //Fail to download manifest file, hot update skipped.
                cannotUpdate = true
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                // this.logLabel.string += "Already up to date with the latest remote version.\n";
                this.changeIndicatorLabel(LanguageMngTs.getSentence(374)) //"Already up to date with the latest remote version."
                isNewest = true
                break;
            case jsb.EventAssetsManager.NEW_VERSION_FOUND:
                // this.logLabel.string += 'New version found,start updating...\n';
                this.changeIndicatorLabel(LanguageMngTs.getSentence(378))   //New version found, start updating.
                this.showUpdateProgress()
                needHotUpdate = true
                break;
            default:
                return;
        }

        this._am.setEventCallback(null);
        this._checkListener = null;
        this._updating = false;

        if(isNewest) cc.find("Canvas").emit("no_need_hotupdate")

        if(needHotUpdate) this.hotUpdate()

        if(cannotUpdate) this.gateMgr.onNoNeedHotUpdate()
    },

    updateCb: function (event) {
        console.log("更新updateCb",JSON.stringify(event))
        var needRestart = false;
        var failed = false;

        let showPercent = 0
        if(event.getPercent() && event.getPercentByFile()){
            showPercent = event.getPercent()
        }

        this.changeUpdateProgress(showPercent)

        switch (event.getEventCode())
        {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                this.setLog('No local manifest file found, hot update skipped.\n')
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_PROGRESSION:

                var msg = event.getMessage();
                if (msg) {
                }
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                this.setLog('Fail to download manifest file, hot update skipped.\n')
                failed = true;
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                this.setLog('Already up to date with the latest remote version.\n')
                this.changeIndicatorLabel(LanguageMngTs.getSentence(381)) //"Update success."
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FINISHED:
                this.setLog('Update finished. ' + event.getMessage()+"\n")
                this.changeIndicatorLabel(LanguageMngTs.getSentence(379))   //Update finished.
                needRestart = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FAILED:
                this.setLog('Update failed. ' + event.getMessage()+"\n")
                this.changeIndicatorLabel(LanguageMngTs.getSentence(380))   //Update failed.Check your network or download the newest apk.
                this._updating = false;
                this._canRetry = true;
                break;
            case jsb.EventAssetsManager.ERROR_UPDATING:
                this.setLog('Asset update error: ' + event.getAssetId() + ', ' + event.getMessage()+"\n")
                this.changeIndicatorLabel('Asset update error: ' + event.getAssetId() + ', ' + event.getMessage())
                break;
            case jsb.EventAssetsManager.ERROR_DECOMPRESS:
                this.setLog(event.getMessage()+"\n")
                break;
            default:
                break;
        }

        if (failed) {
            this._am.setEventCallback(null);
            this._updateListener = null;
            this._updating = false;
            this.retry()
        }

        if (needRestart) {
            this._am.setEventCallback(null);
            this._updateListener = null;
            // Prepend the manifest's search path
            var searchPaths = jsb.fileUtils.getSearchPaths();
            var newPaths = this._am.getLocalManifest().getSearchPaths();
            console.log(JSON.stringify(newPaths));
            Array.prototype.unshift.apply(searchPaths, newPaths);
            // This value will be retrieved and appended to the default search path during game startup,
            // please refer to samples/js-tests/main.js for detailed usage.
            // !!! Re-add the search paths in main.js is very important, otherwise, new scripts won't take effect.
            cc.sys.localStorage.setItem('HotUpdateSearchPaths20200618', JSON.stringify(searchPaths));
            jsb.fileUtils.setSearchPaths(searchPaths);


            console.log("restart game====================================")
            cc.audioEngine.stopAll();
            cc.game.restart();
        }
    },

    loadCustomManifest: function () {
        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
            var manifest = new jsb.Manifest(customManifestStr, this._storagePath);
            this._am.loadLocalManifest(manifest, this._storagePath);
            this.setLog('Using custom manifest')
        }
    },

    retry: function () {
        if (!this._updating && this._canRetry) {
            this._canRetry = false;

            this.setLog('Retry failed Assets...')
            this._am.downloadFailedAssets();
        }
    },

    checkUpdate: function () {
        if (this._updating) {
            this.setLog('Checking or updating ...'+"\n")
            this.changeIndicatorLabel(LanguageMngTs.getSentence(382)) //"Checking..."
            return;
        }
        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
            // Resolve md5 url
            var url = this.manifestUrl.nativeUrl;
            if (cc.loader.md5Pipe) {
                url = cc.loader.md5Pipe.transformURL(url);
            }
            this._am.loadLocalManifest(url);
        }
        if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
            this.setLog('Failed to load local manifest ...'+"\n")
            return;
        }

        // 设置事件回调
        this._am.setEventCallback(this.checkCb.bind(this));
// 取消事件回调
//         this._am.setEventCallback(null);


        // this._checkListener = new jsb.EventListenerAssetsMana

        this._am.checkUpdate();
        this._updating = true;
    },

    hotUpdate: function () {
        if (this._am && !this._updating) {
            this._am.setEventCallback(this.updateCb.bind(this));

            if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
                // Resolve md5 url
                var url = this.manifestUrl.nativeUrl;
                if (cc.loader.md5Pipe) {
                    url = cc.loader.md5Pipe.transformURL(url);
                }
                this._am.loadLocalManifest(url);
            }

            this._failCount = 0;
            this._am.update();
            this._updating = true;
        }
    },

    // use this for initialization
    startHotUpdate: function () {
        // Hot update is only available in Native build
        cc.log("start hot update run")
        if (!cc.sys.isNative) {
            return;
        }
        this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'blackjack-remote-asset');
        cc.log('Storage path for remote asset : ' + this._storagePath);

        // Setup your own version compare handler, versionA and B is versions in string
        // if the return value greater than 0, versionA is greater than B,
        // if the return value equals 0, versionA equals to B,
        // if the return value smaller than 0, versionA is smaller than B.
        this.versionCompareHandle = function (versionA, versionB) {
            cc.gg.dataMgr.version = versionA
            console.log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB);
            var vA = versionA.split('.');
            var vB = versionB.split('.');
            for (var i = 0; i < vA.length; ++i) {
                var a = parseInt(vA[i]);
                var b = parseInt(vB[i] || 0);
                if (a === b) {
                    continue;
                }
                else {
                    return a - b;
                }
            }
            if (vB.length > vA.length) {
                return -1;
            }
            else {
                return 0;
            }
        };

        // Init with empty manifest url for testing custom manifest
        this._am = new jsb.AssetsManager('', this._storagePath, this.versionCompareHandle);

        var panel = this.logLabel;
        let self = this
        // Setup the verification callback, but we don't have md5 check function yet, so only print some message
        // Return true if the verification passed, otherwise return false
        this._am.setVerifyCallback(function (path, asset) {
            // When asset is compressed, we don't need to check its md5, because zip file have been deleted.
            var compressed = asset.compressed;
            // Retrieve the correct md5 value.
            var expectedMD5 = asset.md5;
            // asset.path is relative path and path is absolute.
            var relativePath = asset.path;
            // The size of asset file, but this value could be absent.
            var size = asset.size;
            if (compressed) {
                self.setLog("Verification passed : " + relativePath)
                // panel.string = "Verification passed : " + relativePath;
                return true;
            }
            else {
                self.setLog("Verification passed : " + relativePath + ' (' + expectedMD5 + ')')
                // panel.string = "Verification passed : " + relativePath + ' (' + expectedMD5 + ')';
                return true;
            }
        }.bind(this));

        this.setLog('Hot update is ready, please check or directly update.'+"\n")

        if (cc.sys.os === cc.sys.OS_ANDROID) {
            // Some Android device may slow down the download process when concurrent tasks is too much.
            // The value may not be accurate, please do more test and find what's most suitable for your game.
            this._am.setMaxConcurrentTask(2);
            this.setLog("Max concurrent tasks count have been limited to 2"+"\n")
        }

        this.checkUpdate()
    },

    onDestroy: function () {
        if (this._updateListener) {
            this._am.setEventCallback(null);
            this._updateListener = null;
        }
    }
});